package com.clp.protocol.core.nbytepdu;

import com.clp.protocol.core.pdu.BytePduClip;
import com.clp.protocol.core.pdu.ByteToStringFormat;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 基于字节的帧片段：一个帧片段由一些子的帧片段组成，最终的帧片段为原子的帧片段
 * @param <PC>
 */
public interface NBytePduClip<PC extends NBytePduClip<PC>> extends BytePduClip<PC> {

    /**
     * 解析 {@link ByteBuf} 来刷新并返回自身
     *
     * @param buf
     * @return
     */
    PC refreshFrom(ByteBuf buf);

    /**
     * 从输入流中刷新
     * @param inputStream
     * @return
     * @throws IOException
     */
    @Override
    default PC refreshFrom(InputStream inputStream) throws IOException {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.heapBuffer(512);
        byte[] buffer = new byte[512];
        int len = -1;
        while ((len = inputStream.read(buffer)) != -1) {
            byteBuf.writeBytes(buffer, 0, len);
        }
        PC self = refreshFrom(byteBuf);
        byteBuf.release();
        return self;
    }

    /**
     * 写入 {@link ByteBuf}
     */
    void writeBytesTo(ByteBuf buf);

    /**
     * 写入输出流
     * @param outputStream
     * @throws IOException
     */
    @Override
    default void writeBytesTo(OutputStream outputStream) throws IOException {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.heapBuffer(512);
        writeBytesTo(byteBuf);
        byte[] bytes = new byte[byteBuf.readableBytes()]; byteBuf.readBytes(bytes);
        byteBuf.release();
        outputStream.write(bytes);
    }

    @Override
    default byte[] toBytes() {
        ByteBuf buf = ByteBufAllocator.DEFAULT.heapBuffer(0xFFFF);
        writeBytesTo(buf);
        byte[] retBytes = new byte[buf.readableBytes()];
        buf.readBytes(retBytes);
        buf.release();
        return retBytes;
    }

    /**
     * 获取当前帧片段的打印格式
     * @return
     */
    ToStringFormat getToStringFormat();

    /**
     * 尝试设置打印格式，其所有的子帧片段打印格式都会被应用
     */
    PC setToStringFormat(ToStringFormat toStringFormat);

    /**
     * toString() 方法的打印格式
     */
    interface ToStringFormat {
        ToStringFormat DEFAULT_FORMAT = DescriptionBased.DEFAULT_FORMAT;

        static ToStringFormat ofPrimitive() {
            return PrimitiveBased.INSTANCE;
        }

        static ToStringFormat ofSimpleDescription() {
            return DescriptionBased.SIMPLE_DESCRIPTION;
        }

        static ToStringFormat ofDetailDescription() {
            return DescriptionBased.DETAIL_DESCRIPTION;
        }

        static ToStringFormat ofByteArrayToString(String frameClipSeparator, String byteSeparator, ByteToStringFormat byteFormat) {
            return new ByteArrayBased(frameClipSeparator, byteSeparator, byteFormat);
        }

        String format(NBytePduClip<?> frameClip);

        /**
         * 基于原始的
         */
        @NoArgsConstructor(access = AccessLevel.PROTECTED)
        class PrimitiveBased implements ToStringFormat {
            private static final PrimitiveBased INSTANCE = new PrimitiveBased();

            @Override
            public String format(NBytePduClip<?> frameClip) {
                return frameClip.getClass().getName() + "@" + Integer.toHexString(frameClip.hashCode());
            }
        }

        /**
         * 基于描述的
         */
        enum DescriptionBased implements ToStringFormat {
            SIMPLE_DESCRIPTION() {
                @Override
                public String format(NBytePduClip<?> frameClip) {
                    StringBuilder sb = new StringBuilder();
                    frameClip.writeSimpleDescriptionTo(sb);
                    return sb.toString();
                }
            },
            DETAIL_DESCRIPTION() {
                @Override
                public String format(NBytePduClip<?> frameClip) {
                    StringBuilder sb = new StringBuilder();
                    frameClip.writeDetailDescriptionTo(sb);
                    return sb.toString();
                }
            };

            public static final DescriptionBased DEFAULT_FORMAT = DETAIL_DESCRIPTION;
        }

        /**
         * 基于字节数组的
         */
        @AllArgsConstructor(access = AccessLevel.PRIVATE)
        class ByteArrayBased implements ToStringFormat {
            public static final ByteArrayBased DEFAULT_FORMAT =
                    new ByteArrayBased(" ", " ", ByteToStringFormat.UPPERCASE_HEXADECIMAL);

            private String frameClipByteSeparator;
            private String byteSeparator;
            private ByteToStringFormat byteToStringFormat;

            @Override
            public String format(NBytePduClip<?> frameClip) {
                StringBuilder sb = new StringBuilder();
                frameClip.writeFormattedByteStringsTo(sb, frameClipByteSeparator, byteSeparator, byteToStringFormat);
                return sb.toString();
            }
        }
    }
}
